package org.framework.lazy.cloud.network.heartbeat.server.netty.proxy.socks.advanced;


import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.socksx.v5.DefaultSocks5CommandResponse;
import io.netty.handler.codec.socksx.v5.Socks5AddressType;
import io.netty.handler.codec.socksx.v5.Socks5CommandStatus;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.NettyTransferChannelContext;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.payload.NettyChannelContext;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.payload.NettyProxyMsg;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.proxy.socks.server.AbstractHandleSocksReportClientProxyServerConnectionTransferTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.constant.ProxyMessageType;
import org.framework.lazy.cloud.network.heartbeat.common.decoder.TransferDecoder;
import org.framework.lazy.cloud.network.heartbeat.common.factory.EventLoopGroupFactory;
import org.framework.lazy.cloud.network.heartbeat.common.utils.ChannelAttributeKeyUtils;
import org.framework.lazy.cloud.network.heartbeat.server.netty.proxy.socks.handler.NettySocksClientProxyServerRealHandler;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;


@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Slf4j
@Component
public class ServerHandleSocksReportClientProxyServerConnectTransferTypeAdvanced
        extends AbstractHandleSocksReportClientProxyServerConnectionTransferTypeAdvanced<NettyProxyMsg> {


    /**
     * 处理当前数据
     *
     * @param nettyChannelContext 当前通道
     * @param nettyProxyMsg       通道数据
     */
    @Override
    public void doHandler(NettyChannelContext nettyChannelContext, NettyProxyMsg nettyProxyMsg) {
        Channel transferChannel = nettyChannelContext.channel();


        String host = nettyProxyMsg.getTargetIpString();
        Integer port = Integer.parseInt(nettyProxyMsg.getTargetPortString());
        byte[] data = nettyProxyMsg.getData();
        byte[] visitorId = nettyProxyMsg.getVisitorId();
        byte[] clientId = nettyProxyMsg.getClientId();
        String msgVisitorId = new String(visitorId);
        ChannelAttributeKeyUtils.buildClientId(transferChannel, clientId);
        ChannelAttributeKeyUtils.buildVisitorId(transferChannel, msgVisitorId);

        NettyTransferChannelContext.pushVisitor(transferChannel, msgVisitorId);
        Socks5AddressType socks5AddressType = Socks5AddressType.valueOf(data[0]);

        // 创建真实代理链接
        EventLoopGroup group = EventLoopGroupFactory.createClientWorkGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new TransferDecoder(Integer.MAX_VALUE, 1024 * 1024 * 10));
                        ch.pipeline().addLast(new NettySocksClientProxyServerRealHandler());
                    }
                });
        log.info("准备连接目标服务器，ip = {},port = {}", host, port);
        ChannelFuture f = b.connect(new InetSocketAddress(host, port));
        f.addListener((ChannelFutureListener) future -> {
            Channel realChannel = future.channel();
            if (future.isSuccess()) {

                log.info("目标服务器连接成功");
                // 通道相互绑定
                ChannelAttributeKeyUtils.buildNextChannel(transferChannel, realChannel);
                ChannelAttributeKeyUtils.buildNextChannel(realChannel, transferChannel);

                // 传输通道连接成功下发
                NettyProxyMsg transferNettyProxyMsg = new NettyProxyMsg();

                transferNettyProxyMsg.setType(ProxyMessageType.SOCKS_DISTRIBUTE_CLIENT_PROXY_SERVER_TRANSFER_CONNECTION_SUCCESS_);
                transferChannel.writeAndFlush(transferNettyProxyMsg);

            } else {
                log.error("连接目标服务器失败,address={},port={}", host, port);
                DefaultSocks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.FAILURE, socks5AddressType);
                transferChannel.writeAndFlush(commandResponse);
                realChannel.close();
            }

        });

        // TODO 下发 连接真实服务成功、客户端可以采集数据了

    }

}
